// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_COMPILER_MACHINE_OPERATOR_H_
#define V8_COMPILER_MACHINE_OPERATOR_H_

#include "src/base/compiler-specific.h"
#include "src/base/enum-set.h"
#include "src/base/flags.h"
#include "src/globals.h"
#include "src/machine-type.h"
#include "src/zone/zone.h"

namespace v8 {
namespace internal {
    namespace compiler {

        // Forward declarations.
        struct MachineOperatorGlobalCache;
        class Operator;

        // For operators that are not supported on all platforms.
        class OptionalOperator final {
        public:
            OptionalOperator(bool supported, const Operator* op)
                : supported_(supported)
                , op_(op)
            {
            }

            bool IsSupported() const { return supported_; }
            // Gets the operator only if it is supported.
            const Operator* op() const
            {
                DCHECK(supported_);
                return op_;
            }
            // Always gets the operator, even for unsupported operators. This is useful to
            // use the operator as a placeholder in a graph, for instance.
            const Operator* placeholder() const { return op_; }

        private:
            bool supported_;
            const Operator* const op_;
        };

        // A Load needs a MachineType.
        using LoadRepresentation = MachineType;

        V8_EXPORT_PRIVATE LoadRepresentation LoadRepresentationOf(Operator const*)
            V8_WARN_UNUSED_RESULT;

        // A Store needs a MachineType and a WriteBarrierKind in order to emit the
        // correct write barrier.
        class StoreRepresentation final {
        public:
            StoreRepresentation(MachineRepresentation representation,
                WriteBarrierKind write_barrier_kind)
                : representation_(representation)
                , write_barrier_kind_(write_barrier_kind)
            {
            }

            MachineRepresentation representation() const { return representation_; }
            WriteBarrierKind write_barrier_kind() const { return write_barrier_kind_; }

        private:
            MachineRepresentation representation_;
            WriteBarrierKind write_barrier_kind_;
        };

        V8_EXPORT_PRIVATE bool operator==(StoreRepresentation, StoreRepresentation);
        bool operator!=(StoreRepresentation, StoreRepresentation);

        size_t hash_value(StoreRepresentation);

        V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, StoreRepresentation);

        V8_EXPORT_PRIVATE StoreRepresentation const& StoreRepresentationOf(
            Operator const*) V8_WARN_UNUSED_RESULT;

        // An UnalignedStore needs a MachineType.
        using UnalignedStoreRepresentation = MachineRepresentation;

        UnalignedStoreRepresentation const& UnalignedStoreRepresentationOf(
            Operator const*) V8_WARN_UNUSED_RESULT;

        class StackSlotRepresentation final {
        public:
            StackSlotRepresentation(int size, int alignment)
                : size_(size)
                , alignment_(alignment)
            {
            }

            int size() const { return size_; }
            int alignment() const { return alignment_; }

        private:
            int size_;
            int alignment_;
        };

        V8_EXPORT_PRIVATE bool operator==(StackSlotRepresentation,
            StackSlotRepresentation);
        bool operator!=(StackSlotRepresentation, StackSlotRepresentation);

        size_t hash_value(StackSlotRepresentation);

        V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&,
            StackSlotRepresentation);

        V8_EXPORT_PRIVATE StackSlotRepresentation const& StackSlotRepresentationOf(
            Operator const* op) V8_WARN_UNUSED_RESULT;

        MachineRepresentation AtomicStoreRepresentationOf(Operator const* op)
            V8_WARN_UNUSED_RESULT;

        MachineType AtomicOpType(Operator const* op) V8_WARN_UNUSED_RESULT;

        // Interface for building machine-level operators. These operators are
        // machine-level but machine-independent and thus define a language suitable
        // for generating code to run on architectures such as ia32, x64, arm, etc.
        class V8_EXPORT_PRIVATE MachineOperatorBuilder final
            : public NON_EXPORTED_BASE(ZoneObject) {
        public:
            // Flags that specify which operations are available. This is useful
            // for operations that are unsupported by some back-ends.
            enum Flag : unsigned {
                kNoFlags = 0u,
                kFloat32RoundDown = 1u << 0,
                kFloat64RoundDown = 1u << 1,
                kFloat32RoundUp = 1u << 2,
                kFloat64RoundUp = 1u << 3,
                kFloat32RoundTruncate = 1u << 4,
                kFloat64RoundTruncate = 1u << 5,
                kFloat32RoundTiesEven = 1u << 6,
                kFloat64RoundTiesEven = 1u << 7,
                kFloat64RoundTiesAway = 1u << 8,
                kInt32DivIsSafe = 1u << 9,
                kUint32DivIsSafe = 1u << 10,
                kWord32ShiftIsSafe = 1u << 11,
                kWord32Ctz = 1u << 12,
                kWord64Ctz = 1u << 13,
                kWord32Popcnt = 1u << 14,
                kWord64Popcnt = 1u << 15,
                kWord32ReverseBits = 1u << 16,
                kWord64ReverseBits = 1u << 17,
                kInt32AbsWithOverflow = 1u << 20,
                kInt64AbsWithOverflow = 1u << 21,
                kAllOptionalOps = kFloat32RoundDown | kFloat64RoundDown | kFloat32RoundUp | kFloat64RoundUp | kFloat32RoundTruncate | kFloat64RoundTruncate | kFloat64RoundTiesAway | kFloat32RoundTiesEven | kFloat64RoundTiesEven | kWord32Ctz | kWord64Ctz | kWord32Popcnt | kWord64Popcnt | kWord32ReverseBits | kWord64ReverseBits | kInt32AbsWithOverflow | kInt64AbsWithOverflow
            };
            using Flags = base::Flags<Flag, unsigned>;

            class AlignmentRequirements {
            public:
                enum UnalignedAccessSupport { kNoSupport,
                    kSomeSupport,
                    kFullSupport };

                bool IsUnalignedLoadSupported(MachineRepresentation rep) const
                {
                    return IsUnalignedSupported(unalignedLoadUnsupportedTypes_, rep);
                }

                bool IsUnalignedStoreSupported(MachineRepresentation rep) const
                {
                    return IsUnalignedSupported(unalignedStoreUnsupportedTypes_, rep);
                }

                static AlignmentRequirements FullUnalignedAccessSupport()
                {
                    return AlignmentRequirements(kFullSupport);
                }
                static AlignmentRequirements NoUnalignedAccessSupport()
                {
                    return AlignmentRequirements(kNoSupport);
                }
                static AlignmentRequirements SomeUnalignedAccessUnsupported(
                    base::EnumSet<MachineRepresentation> unalignedLoadUnsupportedTypes,
                    base::EnumSet<MachineRepresentation> unalignedStoreUnsupportedTypes)
                {
                    return AlignmentRequirements(kSomeSupport, unalignedLoadUnsupportedTypes,
                        unalignedStoreUnsupportedTypes);
                }

            private:
                explicit AlignmentRequirements(
                    AlignmentRequirements::UnalignedAccessSupport unalignedAccessSupport,
                    base::EnumSet<MachineRepresentation> unalignedLoadUnsupportedTypes = base::EnumSet<MachineRepresentation>(),
                    base::EnumSet<MachineRepresentation> unalignedStoreUnsupportedTypes = base::EnumSet<MachineRepresentation>())
                    : unalignedSupport_(unalignedAccessSupport)
                    , unalignedLoadUnsupportedTypes_(unalignedLoadUnsupportedTypes)
                    , unalignedStoreUnsupportedTypes_(unalignedStoreUnsupportedTypes)
                {
                }

                bool IsUnalignedSupported(base::EnumSet<MachineRepresentation> unsupported,
                    MachineRepresentation rep) const
                {
                    // All accesses of bytes in memory are aligned.
                    DCHECK_NE(MachineRepresentation::kWord8, rep);
                    switch (unalignedSupport_) {
                    case kFullSupport:
                        return true;
                    case kNoSupport:
                        return false;
                    case kSomeSupport:
                        return !unsupported.contains(rep);
                    }
                    UNREACHABLE();
                }

                const AlignmentRequirements::UnalignedAccessSupport unalignedSupport_;
                const base::EnumSet<MachineRepresentation> unalignedLoadUnsupportedTypes_;
                const base::EnumSet<MachineRepresentation> unalignedStoreUnsupportedTypes_;
            };

            explicit MachineOperatorBuilder(
                Zone* zone,
                MachineRepresentation word = MachineType::PointerRepresentation(),
                Flags supportedOperators = kNoFlags,
                AlignmentRequirements alignmentRequirements = AlignmentRequirements::FullUnalignedAccessSupport());

            const Operator* Comment(const char* msg);
            const Operator* DebugAbort();
            const Operator* DebugBreak();
            const Operator* UnsafePointerAdd();

            const Operator* Word32And();
            const Operator* Word32Or();
            const Operator* Word32Xor();
            const Operator* Word32Shl();
            const Operator* Word32Shr();
            const Operator* Word32Sar();
            const Operator* Word32Ror();
            const Operator* Word32Equal();
            const Operator* Word32Clz();
            const OptionalOperator Word32Ctz();
            const OptionalOperator Word32Popcnt();
            const OptionalOperator Word64Popcnt();
            const OptionalOperator Word32ReverseBits();
            const OptionalOperator Word64ReverseBits();
            const Operator* Word32ReverseBytes();
            const Operator* Word64ReverseBytes();
            const OptionalOperator Int32AbsWithOverflow();
            const OptionalOperator Int64AbsWithOverflow();

            // Return true if the target's Word32 shift implementation is directly
            // compatible with JavaScript's specification. Otherwise, we have to manually
            // generate a mask with 0x1f on the amount ahead of generating the shift.
            bool Word32ShiftIsSafe() const { return flags_ & kWord32ShiftIsSafe; }

            const Operator* Word64And();
            const Operator* Word64Or();
            const Operator* Word64Xor();
            const Operator* Word64Shl();
            const Operator* Word64Shr();
            const Operator* Word64Sar();
            const Operator* Word64Ror();
            const Operator* Word64Clz();
            const OptionalOperator Word64Ctz();
            const Operator* Word64Equal();

            const Operator* Int32PairAdd();
            const Operator* Int32PairSub();
            const Operator* Int32PairMul();
            const Operator* Word32PairShl();
            const Operator* Word32PairShr();
            const Operator* Word32PairSar();

            const Operator* Int32Add();
            const Operator* Int32AddWithOverflow();
            const Operator* Int32Sub();
            const Operator* Int32SubWithOverflow();
            const Operator* Int32Mul();
            const Operator* Int32MulWithOverflow();
            const Operator* Int32MulHigh();
            const Operator* Int32Div();
            const Operator* Int32Mod();
            const Operator* Int32LessThan();
            const Operator* Int32LessThanOrEqual();
            const Operator* Uint32Div();
            const Operator* Uint32LessThan();
            const Operator* Uint32LessThanOrEqual();
            const Operator* Uint32Mod();
            const Operator* Uint32MulHigh();
            bool Int32DivIsSafe() const { return flags_ & kInt32DivIsSafe; }
            bool Uint32DivIsSafe() const { return flags_ & kUint32DivIsSafe; }

            const Operator* Int64Add();
            const Operator* Int64AddWithOverflow();
            const Operator* Int64Sub();
            const Operator* Int64SubWithOverflow();
            const Operator* Int64Mul();
            const Operator* Int64Div();
            const Operator* Int64Mod();
            const Operator* Int64LessThan();
            const Operator* Int64LessThanOrEqual();
            const Operator* Uint64Div();
            const Operator* Uint64LessThan();
            const Operator* Uint64LessThanOrEqual();
            const Operator* Uint64Mod();

            // This operator reinterprets the bits of a tagged pointer as word.
            const Operator* BitcastTaggedToWord();

            // This operator reinterprets the bits of a tagged MaybeObject pointer as
            // word.
            const Operator* BitcastMaybeObjectToWord();

            // This operator reinterprets the bits of a word as tagged pointer.
            const Operator* BitcastWordToTagged();

            // This operator reinterprets the bits of a word as a Smi.
            const Operator* BitcastWordToTaggedSigned();

            // JavaScript float64 to int32/uint32 truncation.
            const Operator* TruncateFloat64ToWord32();

            // These operators change the representation of numbers while preserving the
            // value of the number. Narrowing operators assume the input is representable
            // in the target type and are *not* defined for other inputs.
            // Use narrowing change operators only when there is a static guarantee that
            // the input value is representable in the target value.
            const Operator* ChangeFloat32ToFloat64();
            const Operator* ChangeFloat64ToInt32(); // narrowing
            const Operator* ChangeFloat64ToInt64();
            const Operator* ChangeFloat64ToUint32(); // narrowing
            const Operator* ChangeFloat64ToUint64();
            const Operator* TruncateFloat64ToInt64();
            const Operator* TruncateFloat64ToUint32();
            const Operator* TruncateFloat32ToInt32();
            const Operator* TruncateFloat32ToUint32();
            const Operator* TryTruncateFloat32ToInt64();
            const Operator* TryTruncateFloat64ToInt64();
            const Operator* TryTruncateFloat32ToUint64();
            const Operator* TryTruncateFloat64ToUint64();
            const Operator* ChangeInt32ToFloat64();
            const Operator* ChangeInt32ToInt64();
            const Operator* ChangeInt64ToFloat64();
            const Operator* ChangeUint32ToFloat64();
            const Operator* ChangeUint32ToUint64();
            const Operator* ChangeTaggedToCompressed();
            const Operator* ChangeTaggedPointerToCompressedPointer();
            const Operator* ChangeTaggedSignedToCompressedSigned();
            const Operator* ChangeCompressedToTagged();
            const Operator* ChangeCompressedPointerToTaggedPointer();
            const Operator* ChangeCompressedSignedToTaggedSigned();

            // These operators truncate or round numbers, both changing the representation
            // of the number and mapping multiple input values onto the same output value.
            const Operator* TruncateFloat64ToFloat32();
            const Operator* TruncateInt64ToInt32();
            const Operator* RoundFloat64ToInt32();
            const Operator* RoundInt32ToFloat32();
            const Operator* RoundInt64ToFloat32();
            const Operator* RoundInt64ToFloat64();
            const Operator* RoundUint32ToFloat32();
            const Operator* RoundUint64ToFloat32();
            const Operator* RoundUint64ToFloat64();

            // These operators reinterpret the bits of a floating point number as an
            // integer and vice versa.
            const Operator* BitcastFloat32ToInt32();
            const Operator* BitcastFloat64ToInt64();
            const Operator* BitcastInt32ToFloat32();
            const Operator* BitcastInt64ToFloat64();

            // These operators sign-extend to Int32/Int64
            const Operator* SignExtendWord8ToInt32();
            const Operator* SignExtendWord16ToInt32();
            const Operator* SignExtendWord8ToInt64();
            const Operator* SignExtendWord16ToInt64();
            const Operator* SignExtendWord32ToInt64();

            // Floating point operators always operate with IEEE 754 round-to-nearest
            // (single-precision).
            const Operator* Float32Add();
            const Operator* Float32Sub();
            const Operator* Float32Mul();
            const Operator* Float32Div();
            const Operator* Float32Sqrt();

            // Floating point operators always operate with IEEE 754 round-to-nearest
            // (double-precision).
            const Operator* Float64Add();
            const Operator* Float64Sub();
            const Operator* Float64Mul();
            const Operator* Float64Div();
            const Operator* Float64Mod();
            const Operator* Float64Sqrt();

            // Floating point comparisons complying to IEEE 754 (single-precision).
            const Operator* Float32Equal();
            const Operator* Float32LessThan();
            const Operator* Float32LessThanOrEqual();

            // Floating point comparisons complying to IEEE 754 (double-precision).
            const Operator* Float64Equal();
            const Operator* Float64LessThan();
            const Operator* Float64LessThanOrEqual();

            // Floating point min/max complying to EcmaScript 6 (double-precision).
            const Operator* Float64Max();
            const Operator* Float64Min();
            // Floating point min/max complying to WebAssembly (single-precision).
            const Operator* Float32Max();
            const Operator* Float32Min();

            // Floating point abs complying to IEEE 754 (single-precision).
            const Operator* Float32Abs();

            // Floating point abs complying to IEEE 754 (double-precision).
            const Operator* Float64Abs();

            // Floating point rounding.
            const OptionalOperator Float32RoundDown();
            const OptionalOperator Float64RoundDown();
            const OptionalOperator Float32RoundUp();
            const OptionalOperator Float64RoundUp();
            const OptionalOperator Float32RoundTruncate();
            const OptionalOperator Float64RoundTruncate();
            const OptionalOperator Float64RoundTiesAway();
            const OptionalOperator Float32RoundTiesEven();
            const OptionalOperator Float64RoundTiesEven();

            // Floating point neg.
            const Operator* Float32Neg();
            const Operator* Float64Neg();

            // Floating point trigonometric functions (double-precision).
            const Operator* Float64Acos();
            const Operator* Float64Acosh();
            const Operator* Float64Asin();
            const Operator* Float64Asinh();
            const Operator* Float64Atan();
            const Operator* Float64Atan2();
            const Operator* Float64Atanh();
            const Operator* Float64Cos();
            const Operator* Float64Cosh();
            const Operator* Float64Sin();
            const Operator* Float64Sinh();
            const Operator* Float64Tan();
            const Operator* Float64Tanh();

            // Floating point exponential functions (double-precision).
            const Operator* Float64Exp();
            const Operator* Float64Expm1();
            const Operator* Float64Pow();

            // Floating point logarithm (double-precision).
            const Operator* Float64Log();
            const Operator* Float64Log1p();
            const Operator* Float64Log2();
            const Operator* Float64Log10();

            // Floating point cube root (double-precision).
            const Operator* Float64Cbrt();

            // Floating point bit representation.
            const Operator* Float64ExtractLowWord32();
            const Operator* Float64ExtractHighWord32();
            const Operator* Float64InsertLowWord32();
            const Operator* Float64InsertHighWord32();

            // Change signalling NaN to quiet NaN.
            // Identity for any input that is not signalling NaN.
            const Operator* Float64SilenceNaN();

            // SIMD operators.
            const Operator* F32x4Splat();
            const Operator* F32x4ExtractLane(int32_t);
            const Operator* F32x4ReplaceLane(int32_t);
            const Operator* F32x4SConvertI32x4();
            const Operator* F32x4UConvertI32x4();
            const Operator* F32x4Abs();
            const Operator* F32x4Neg();
            const Operator* F32x4RecipApprox();
            const Operator* F32x4RecipSqrtApprox();
            const Operator* F32x4Add();
            const Operator* F32x4AddHoriz();
            const Operator* F32x4Sub();
            const Operator* F32x4Mul();
            const Operator* F32x4Div();
            const Operator* F32x4Min();
            const Operator* F32x4Max();
            const Operator* F32x4Eq();
            const Operator* F32x4Ne();
            const Operator* F32x4Lt();
            const Operator* F32x4Le();

            const Operator* I32x4Splat();
            const Operator* I32x4ExtractLane(int32_t);
            const Operator* I32x4ReplaceLane(int32_t);
            const Operator* I32x4SConvertF32x4();
            const Operator* I32x4SConvertI16x8Low();
            const Operator* I32x4SConvertI16x8High();
            const Operator* I32x4Neg();
            const Operator* I32x4Shl(int32_t);
            const Operator* I32x4ShrS(int32_t);
            const Operator* I32x4Add();
            const Operator* I32x4AddHoriz();
            const Operator* I32x4Sub();
            const Operator* I32x4Mul();
            const Operator* I32x4MinS();
            const Operator* I32x4MaxS();
            const Operator* I32x4Eq();
            const Operator* I32x4Ne();
            const Operator* I32x4GtS();
            const Operator* I32x4GeS();

            const Operator* I32x4UConvertF32x4();
            const Operator* I32x4UConvertI16x8Low();
            const Operator* I32x4UConvertI16x8High();
            const Operator* I32x4ShrU(int32_t);
            const Operator* I32x4MinU();
            const Operator* I32x4MaxU();
            const Operator* I32x4GtU();
            const Operator* I32x4GeU();

            const Operator* I16x8Splat();
            const Operator* I16x8ExtractLane(int32_t);
            const Operator* I16x8ReplaceLane(int32_t);
            const Operator* I16x8SConvertI8x16Low();
            const Operator* I16x8SConvertI8x16High();
            const Operator* I16x8Neg();
            const Operator* I16x8Shl(int32_t);
            const Operator* I16x8ShrS(int32_t);
            const Operator* I16x8SConvertI32x4();
            const Operator* I16x8Add();
            const Operator* I16x8AddSaturateS();
            const Operator* I16x8AddHoriz();
            const Operator* I16x8Sub();
            const Operator* I16x8SubSaturateS();
            const Operator* I16x8Mul();
            const Operator* I16x8MinS();
            const Operator* I16x8MaxS();
            const Operator* I16x8Eq();
            const Operator* I16x8Ne();
            const Operator* I16x8GtS();
            const Operator* I16x8GeS();

            const Operator* I16x8UConvertI8x16Low();
            const Operator* I16x8UConvertI8x16High();
            const Operator* I16x8ShrU(int32_t);
            const Operator* I16x8UConvertI32x4();
            const Operator* I16x8AddSaturateU();
            const Operator* I16x8SubSaturateU();
            const Operator* I16x8MinU();
            const Operator* I16x8MaxU();
            const Operator* I16x8GtU();
            const Operator* I16x8GeU();

            const Operator* I8x16Splat();
            const Operator* I8x16ExtractLane(int32_t);
            const Operator* I8x16ReplaceLane(int32_t);
            const Operator* I8x16Neg();
            const Operator* I8x16Shl(int32_t);
            const Operator* I8x16ShrS(int32_t);
            const Operator* I8x16SConvertI16x8();
            const Operator* I8x16Add();
            const Operator* I8x16AddSaturateS();
            const Operator* I8x16Sub();
            const Operator* I8x16SubSaturateS();
            const Operator* I8x16Mul();
            const Operator* I8x16MinS();
            const Operator* I8x16MaxS();
            const Operator* I8x16Eq();
            const Operator* I8x16Ne();
            const Operator* I8x16GtS();
            const Operator* I8x16GeS();

            const Operator* I8x16ShrU(int32_t);
            const Operator* I8x16UConvertI16x8();
            const Operator* I8x16AddSaturateU();
            const Operator* I8x16SubSaturateU();
            const Operator* I8x16MinU();
            const Operator* I8x16MaxU();
            const Operator* I8x16GtU();
            const Operator* I8x16GeU();

            const Operator* S128Load();
            const Operator* S128Store();

            const Operator* S128Zero();
            const Operator* S128And();
            const Operator* S128Or();
            const Operator* S128Xor();
            const Operator* S128Not();
            const Operator* S128Select();

            const Operator* S8x16Shuffle(const uint8_t shuffle[16]);

            const Operator* S1x4AnyTrue();
            const Operator* S1x4AllTrue();
            const Operator* S1x8AnyTrue();
            const Operator* S1x8AllTrue();
            const Operator* S1x16AnyTrue();
            const Operator* S1x16AllTrue();

            // load [base + index]
            const Operator* Load(LoadRepresentation rep);
            const Operator* PoisonedLoad(LoadRepresentation rep);
            const Operator* ProtectedLoad(LoadRepresentation rep);

            // store [base + index], value
            const Operator* Store(StoreRepresentation rep);
            const Operator* ProtectedStore(MachineRepresentation rep);

            // unaligned load [base + index]
            const Operator* UnalignedLoad(LoadRepresentation rep);

            // unaligned store [base + index], value
            const Operator* UnalignedStore(UnalignedStoreRepresentation rep);

            const Operator* StackSlot(int size, int alignment = 0);
            const Operator* StackSlot(MachineRepresentation rep, int alignment = 0);

            // Destroy value by masking when misspeculating.
            const Operator* TaggedPoisonOnSpeculation();
            const Operator* Word32PoisonOnSpeculation();
            const Operator* Word64PoisonOnSpeculation();

            // Access to the machine stack.
            const Operator* LoadStackPointer();
            const Operator* LoadFramePointer();
            const Operator* LoadParentFramePointer();

            // atomic-load [base + index]
            const Operator* Word32AtomicLoad(LoadRepresentation rep);
            // atomic-load [base + index]
            const Operator* Word64AtomicLoad(LoadRepresentation rep);
            // atomic-store [base + index], value
            const Operator* Word32AtomicStore(MachineRepresentation rep);
            // atomic-store [base + index], value
            const Operator* Word64AtomicStore(MachineRepresentation rep);
            // atomic-exchange [base + index], value
            const Operator* Word32AtomicExchange(MachineType type);
            // atomic-exchange [base + index], value
            const Operator* Word64AtomicExchange(MachineType type);
            // atomic-compare-exchange [base + index], old_value, new_value
            const Operator* Word32AtomicCompareExchange(MachineType type);
            // atomic-compare-exchange [base + index], old_value, new_value
            const Operator* Word64AtomicCompareExchange(MachineType type);
            // atomic-add [base + index], value
            const Operator* Word32AtomicAdd(MachineType type);
            // atomic-sub [base + index], value
            const Operator* Word32AtomicSub(MachineType type);
            // atomic-and [base + index], value
            const Operator* Word32AtomicAnd(MachineType type);
            // atomic-or [base + index], value
            const Operator* Word32AtomicOr(MachineType type);
            // atomic-xor [base + index], value
            const Operator* Word32AtomicXor(MachineType rep);
            // atomic-add [base + index], value
            const Operator* Word64AtomicAdd(MachineType rep);
            // atomic-sub [base + index], value
            const Operator* Word64AtomicSub(MachineType type);
            // atomic-and [base + index], value
            const Operator* Word64AtomicAnd(MachineType type);
            // atomic-or [base + index], value
            const Operator* Word64AtomicOr(MachineType type);
            // atomic-xor [base + index], value
            const Operator* Word64AtomicXor(MachineType rep);
            // atomic-pair-load [base + index]
            const Operator* Word32AtomicPairLoad();
            // atomic-pair-sub [base + index], value_high, value-low
            const Operator* Word32AtomicPairStore();
            // atomic-pair-add [base + index], value_high, value_low
            const Operator* Word32AtomicPairAdd();
            // atomic-pair-sub [base + index], value_high, value-low
            const Operator* Word32AtomicPairSub();
            // atomic-pair-and [base + index], value_high, value_low
            const Operator* Word32AtomicPairAnd();
            // atomic-pair-or [base + index], value_high, value_low
            const Operator* Word32AtomicPairOr();
            // atomic-pair-xor [base + index], value_high, value_low
            const Operator* Word32AtomicPairXor();
            // atomic-pair-exchange [base + index], value_high, value_low
            const Operator* Word32AtomicPairExchange();
            // atomic-pair-compare-exchange [base + index], old_value_high, old_value_low,
            // new_value_high, new_value_low
            const Operator* Word32AtomicPairCompareExchange();

            // Target machine word-size assumed by this builder.
            bool Is32() const { return word() == MachineRepresentation::kWord32; }
            bool Is64() const { return word() == MachineRepresentation::kWord64; }
            MachineRepresentation word() const { return word_; }

            bool UnalignedLoadSupported(MachineRepresentation rep)
            {
                return alignment_requirements_.IsUnalignedLoadSupported(rep);
            }

            bool UnalignedStoreSupported(MachineRepresentation rep)
            {
                return alignment_requirements_.IsUnalignedStoreSupported(rep);
            }

// Pseudo operators that translate to 32/64-bit operators depending on the
// word-size of the target machine assumed by this builder.
#define PSEUDO_OP_LIST(V)        \
    V(Word, And)                 \
    V(Word, Or)                  \
    V(Word, Xor)                 \
    V(Word, Shl)                 \
    V(Word, Shr)                 \
    V(Word, Sar)                 \
    V(Word, Ror)                 \
    V(Word, Clz)                 \
    V(Word, Equal)               \
    V(Word, PoisonOnSpeculation) \
    V(Int, Add)                  \
    V(Int, Sub)                  \
    V(Int, Mul)                  \
    V(Int, Div)                  \
    V(Int, Mod)                  \
    V(Int, LessThan)             \
    V(Int, LessThanOrEqual)      \
    V(Uint, Div)                 \
    V(Uint, LessThan)            \
    V(Uint, Mod)
#define PSEUDO_OP(Prefix, Suffix)                                    \
    const Operator* Prefix##Suffix()                                 \
    {                                                                \
        return Is32() ? Prefix##32##Suffix() : Prefix##64##Suffix(); \
    }
            PSEUDO_OP_LIST(PSEUDO_OP)
#undef PSEUDO_OP
#undef PSEUDO_OP_LIST

        private:
            Zone* zone_;
            MachineOperatorGlobalCache const& cache_;
            MachineRepresentation const word_;
            Flags const flags_;
            AlignmentRequirements const alignment_requirements_;

            DISALLOW_COPY_AND_ASSIGN(MachineOperatorBuilder);
        };

        DEFINE_OPERATORS_FOR_FLAGS(MachineOperatorBuilder::Flags)

    } // namespace compiler
} // namespace internal
} // namespace v8

#endif // V8_COMPILER_MACHINE_OPERATOR_H_
